package org.springblade.modules.alimqtt;

import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.modules.alimqtt.annotation.AliListener;
import org.springblade.modules.alimqtt.annotation.AliMsgService;
import org.springblade.modules.alimqtt.message.MsgPayload;
import org.springblade.modules.alimqtt.util.BeanFactoryUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 阿里云消息派发控制器
 */

@ConditionalOnProperty(name ="aliyun.mqtt.enable", havingValue = "true",matchIfMissing = false)
@Component
@Slf4j
public class AliyunMsgDispatcher {

	@Lazy
	@Resource
	private AliyunMsgDispatcher _self;

    public Map<String, Object> getMqttServices() {
		return BeanFactoryUtils.getBeansByAnnotation(AliMsgService.class);
    }



    public void dispatch(String receivedTopic, MsgPayload payload) {
        // 在这里 我们根据不同的 主题 分发不同的消息
		Map<String, Object> mqttServices = getMqttServices();
		for (Map.Entry<String, Object> entry : mqttServices.entrySet()) {
            // 把所有带有 @MqttService 的类遍历
            Class<?> clazz = entry.getValue().getClass();
            // 获取他所有方法
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                if (method.isAnnotationPresent(AliListener.class)) {
                    // 如果这个方法有 这个注解
                    AliListener aliListener = method.getAnnotation(AliListener.class);
                    if (peakMatch(receivedTopic, aliListener.topic())) {
                        // 并且 这个 topic 匹配成功
						_self.invokeMethodAsync(method, clazz, payload);
                    }
                }
            }
        }
    }


    /**
     * mqtt 订阅的主题与我实际的主题是否匹配
     *
     * @param topic   是实际的主题
     * @param pattern 是我订阅的主题 可以是通配符模式
     * @return 是否匹配
     */
    public static boolean peakMatch(String topic, String pattern) {

        if ((topic == null) || (pattern == null)) {
            return false;
        }

        if (topic.equals(pattern)) {
            // 完全相等是肯定匹配的
            return true;
        }

        if ("#".equals(pattern)) {
            // # 号代表所有主题  肯定匹配的
            return true;
        }
        String[] splitTopic = topic.split("/");
        String[] splitPattern = pattern.split("/");

        boolean match = true;

        // 如果包含 # 则只需要判断 # 前面的
        for (int i = 0; i < splitPattern.length; i++) {
            if (!"#".equals(splitPattern[i])) {
                // 不是# 号 正常判断
                if (i >= splitTopic.length) {
                    // 此时长度不相等 不匹配
                    match = false;
                    break;
                }
                if (!splitTopic[i].equals(splitPattern[i]) && !"+".equals(splitPattern[i])) {
                    // 不相等 且不等于 +
                    match = false;
                    break;
                }
            } else {
                // 是# 号  肯定匹配的
                break;
            }
        }

        return match;
    }


	@Async("coffeeTaskExecutor")
	public void invokeMethodAsync(Method method, Class<?> clazz, Object... args) {
		try {
			method.invoke(SpringUtil.getBean(clazz), args);
		} catch (IllegalAccessException | InvocationTargetException e) {
			log.error("执行 {} 方法出现错误", method, e);
		}
	}
}
